package com.koron.common.core.business.datadict.service;

import com.koron.bean.base.Response;
import com.koron.bean.util.RedisUtils;
import com.koron.common.core.business.datadict.bean.po.SysDataDict;
import com.koron.common.core.business.datadict.bean.po.SysDataDictDetail;
import com.koron.common.core.business.datadict.bean.query.SysDataDictQuery;
import com.koron.common.core.business.datadict.mapper.SysDataDictMapper;
import com.koron.common.core.util.CodeTools;
import com.koron.common.core.util.UpdateRedis;
import org.koron.ebs.mybatis.SessionFactory;
import org.koron.ebs.mybatis.TaskAnnotation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

/**
 * 系统管理-数据字典{@code SysDataDict}表服务实现类
 *
 * <p>方法1-checkBeforeInsert：增数据，不能插入重复数据字典编码</p>
 * <p>方法2-deleteById：通过id逻辑删除数据</p>
 * <p>方法2-checkBeforeUpdate：修改数据</p>
 * <p>方法4-getDictionaryList：通过classifyId和分页参数来数据字典</p>
 * <p>方法5-getByClassifyIdAndCode：根据传入的classifyId和code来返回对应的数据字典及其数据字典详情</p>
 * <p>方法6-queryAll：查询所有数据的数据字典</p>
 * <p>方法7-getById：根据id查询对应的数据</p>
 *
 * @author 朱超
 * @since 2021-08-27
 */
@Service
public class SysDataDictService {

    @Autowired
    private SysDataDictClassifyService sysDataDictClassifyService;

    @Autowired
    private SysDataDictDetailService sysDataDictDetailService;

    @Autowired
    private UpdateRedis updateRedis;

    private static final String key_prefix = "eam:dataDict:";

    /**
     * 新增数据，不能插入重复数据字典编码
     *
     * @param sysDataDict 实例对象
     * @param factory
     * @throws {@code Internal Server Error} 字典编码不能重复
     * @return Response对象
     * @see Response
     * @version 1.0
     */
    @TaskAnnotation("checkBeforeInsert")
    public Response checkBeforeInsert(SessionFactory factory, SysDataDict sysDataDict) {
        SysDataDictMapper sysDataDictMapper = factory.getMapper(SysDataDictMapper.class);
        String classifyId = sysDataDict.getClassifyId();
        String code = sysDataDict.getCode();
        String name = sysDataDict.getName();

        // 1. 同一数据字典分类下，字典编码不能重复
        SysDataDictQuery sysDataDictQuery = new SysDataDictQuery();
        sysDataDictQuery.setClassifyId(classifyId);
        sysDataDictQuery.setCode(code);
        SysDataDict uniqueCode = sysDataDictMapper.getSingle(sysDataDictQuery);
        if (uniqueCode != null) {
            return Response.fail("同一数据字典分类下，字典编码不能重复");
        }
        // 2. 同一数据字典分类下，字典名称不能重复
        // 2.1 复用查询条件，将code置空
        sysDataDictQuery.setCode(null);
        sysDataDictQuery.setName(name);
        // 2.2 查询数据
        SysDataDict uniqueName = sysDataDictMapper.getSingle(sysDataDictQuery);
        if (uniqueName != null) {
            return Response.fail("同一数据字典分类下，字典名称不能重复");
        }
        // 3. 设置id
        sysDataDict.setId(CodeTools.getCode32());
        // 4. 设置deleteFlag
        sysDataDict.setDeleteFlag(0);
        // 5. 插入数据
        factory.getMapper(SysDataDictMapper.class).insert(sysDataDict);
        // 6. 更新redis
        updateRedis.setDataDictInRedis(sysDataDict);

        return Response.success(sysDataDict);
    }

    /**
     * 通过id逻辑删除数据
     *
     * @param id 主键
     * @param factory
     * @throws {@code Internal Server Error} 不允许删除有详情的数据字典
     * @return Response对象
     * @see Response
     * @version 1.0
     */
    @TaskAnnotation("deleteById")
    public Response deleteById(SessionFactory factory, String id) {
        SysDataDictMapper sysDataDictMapper = factory.getMapper(SysDataDictMapper.class);

        // 1. 根据id查看s_dictionary_detail中是否还有关联数据
        List<SysDataDictDetail> sysDataDictDetailList = sysDataDictDetailService.getByDictionary(factory,id);
        if (sysDataDictDetailList.size() > 0) {
            return Response.fail("不允许删除有数据详情的字典");
        }
        // 2. 根据id查出数据，classifyId,code
        SysDataDictQuery sysDataDictQuery = new SysDataDictQuery();
        sysDataDictQuery.setId(id);
        SysDataDict sysDataDict = sysDataDictMapper.getSingle(sysDataDictQuery);
        String classifyId = sysDataDict.getClassifyId();
        String code = sysDataDict.getCode();
        // 3. 获取redisKey
        String redisKey = key_prefix + classifyId + ":" + code;
        // 4. 逻辑删除数据字典
        sysDataDict.setDeleteFlag(1);
        sysDataDictMapper.update(sysDataDict);
        // 5. redis删除
        RedisUtils.delete(redisKey);

        return Response.success("删除成功");
    }

    /**
     * 修改数据
     *
     * @param sysDataDict 实例对象
     * @param factory
     * @throws {@code Internal Server Error} 字典编码不能重复
     * @return Response对象
     * @see Response
     * @version 1.0
     */
    @TaskAnnotation("checkBeforeUpdate")
    public Response checkBeforeUpdate(SessionFactory factory, SysDataDict sysDataDict) {
        SysDataDictMapper sysDataDictMapper = factory.getMapper(SysDataDictMapper.class);
        String id = sysDataDict.getId();
        String classifyId = sysDataDict.getClassifyId();
        String code = sysDataDict.getCode();
        String name = sysDataDict.getName();

        // 1. 同一数据字典分类下，字典编码不能重复，自己除外
        SysDataDictQuery sysDataDictQuery = new SysDataDictQuery();
        sysDataDictQuery.setClassifyId(classifyId);
        sysDataDictQuery.setCode(code);
        SysDataDict uniqueKey = sysDataDictMapper.getSingle(sysDataDictQuery);
        if (uniqueKey != null && !uniqueKey.getId().equals(id)) {
            return Response.fail("同一数据字典分类下，字典编码不能重复！");
        }
        // 2. 同一数据字典分类下，字典名称不能重复，自己除外
        // 2.1 复用查询条件，将code置空
        sysDataDictQuery.setCode(null);
        sysDataDictQuery.setName(name);
        // 2.2 查出数据并判断
        SysDataDict uniqueName = sysDataDictMapper.getSingle(sysDataDictQuery);
        if (uniqueName != null && !uniqueName.getId().equals(id)) {
            return Response.fail("同一数据字典分类下，字典名称不能重复！");
        }
        // 3. 通过前面的判断，说明可以更新...如果更新了字典编码，因为redisKey的生成规则，需要把redis中原来的数据删除
        // 3.1 复用查询条件，将classifyId，name置空,并设置id
        sysDataDictQuery.setClassifyId(null);
        sysDataDictQuery.setName(null);
        sysDataDictQuery.setId(id);
        // 3.2 根据id查出现在的数据
        SysDataDict formerDataDict = sysDataDictMapper.getSingle(sysDataDictQuery);
        // 3.3 只有当字典编码变更的时候，redisKey才会变更
        if (!formerDataDict.getCode().equals(code)) {
            // 3.4 获取之前的redisKey
            String formerRedisKey = key_prefix + classifyId + ":" + formerDataDict.getCode();
            // 3.5 redis删除原来的key
            RedisUtils.delete(formerRedisKey);
        }
        // 4. 更新数据库
        sysDataDictMapper.update(sysDataDict);
        // 5. 更新redis
        // 5.1 获取对应的数据字典详情列表
        List<SysDataDictDetail> sysDataDictDetailList = sysDataDictDetailService.getByDictionary(factory,id);
        sysDataDict.setSysDataDictDetailList(sysDataDictDetailList);
        // 5.2 更新redis
        updateRedis.setDataDictInRedis(sysDataDict);

        return Response.success("更新成功");
    }

    /**
     * 通过classifyId和分页参数来数据字典
     *
     * @param sysDataDictQuery
     * @param factory
     * @return Response对象
     * @see Response
     * @version 1.0
     */
    @TaskAnnotation("getDictionaryList")
    public Response getDictionaryList(SessionFactory factory, SysDataDictQuery sysDataDictQuery) {
        SysDataDictMapper sysDataDictMapper = factory.getMapper(SysDataDictMapper.class);
        // 1. 数据字典编码添加
        sysDataDictQuery.setCode(sysDataDictQuery.getName());
        // 3. 查询结果
        List<SysDataDict> result = sysDataDictMapper.getDictionaryList(sysDataDictQuery);
        // 4. 给结果数据添加上分类名称
        for (SysDataDict sysDataDict:result) {
            String classifyName = sysDataDictClassifyService.getNameById(factory, sysDataDict.getClassifyId());
            sysDataDict.setClassifyName(classifyName);
        }
        // 5. 查询结果总数
        Integer total = sysDataDictMapper.getTotal(sysDataDictQuery);

        return Response.success("查询成功",result,total.longValue());
    }

    /**
     * 根据传入的classifyId和code来返回对应的数据字典及其数据字典详情
     * 1. 先尝试从redis中获取数据
     * 2. 如果redis中没有数据，从数据库中获取数据
     * 3. 如果从数据库中获取数据，更新该数据至redis
     *
     * @param factory
     * @param classifyId 数据字典分类id
     * @param code
     *
     * @return SysDataDict
     * @see SysDataDict
     * @version 1.0
     */
    @TaskAnnotation("getByClassifyIdAndCode")
    public SysDataDict getByClassifyIdAndCode(SessionFactory factory, String classifyId, String code) {
        SysDataDict sysDataDict = new SysDataDict();
        String redisKey = key_prefix + classifyId + ":" + code;

        // 1. 尝试从redis中获取数据
        Map<Object, Object> redisValue = RedisUtils.hmget(redisKey);
        if (redisValue.size() > 0 && redisValue.get("sysDataDictDetailList") != null) {
            // 2. 将redis中获取的数据赋值到实例中
            sysDataDict.setId((String) redisValue.get("id"));
            sysDataDict.setClassifyId((String) redisValue.get("classifyId"));
            sysDataDict.setCode((String) redisValue.get("code"));
            sysDataDict.setName((String) redisValue.get("name"));
            sysDataDict.setSysDataDictDetailList((List<SysDataDictDetail>) redisValue.get("sysDataDictDetailList"));
        } else {
            // 3. 如果redis中没有，则从数据库获取
            SysDataDictMapper sysDataDictMapper = factory.getMapper(SysDataDictMapper.class);
            sysDataDict = sysDataDictMapper.getByClassifyIdAndCode(classifyId,code);
            // 3.1 根据sysDataDict的id获取其对应的详情，并放到实例中
            if (sysDataDict == null) {
                throw new IllegalArgumentException("数据字典【" + classifyId + ":" + code + "】不能为空");
            }
            String dictionary = sysDataDict.getId();
            List<SysDataDictDetail> sysDataDictDetailList = sysDataDictDetailService.getByDictionary(factory,dictionary);
            sysDataDict.setSysDataDictDetailList(sysDataDictDetailList);
            // 4. 更新redis
            updateRedis.setDataDictInRedis(sysDataDict);
        }

        return sysDataDict;
    }

    /**
     * 查询所有数据的数据字典
     *
     * @param factory
     * @param sysDataDict
     * @return List<SysDataDict>：s_dictionary_type表中的所有数据字典数据
     * @version 1.0
     */
    public List<SysDataDict> queryAll(SessionFactory factory, SysDataDict sysDataDict) {
        return factory.getMapper(SysDataDictMapper.class).queryAll(sysDataDict);
    }

    /**
     * 根据id查询对应的数据
     *
     * @param factory
     * @param id
     *
     * @return sysDataDict
     * @see SysDataDict
     * @version 1.0
     */
    public SysDataDict getById(SessionFactory factory, String id) {
        SysDataDictMapper sysDataDictMapper = factory.getMapper(SysDataDictMapper.class);
        SysDataDictQuery sysDataDictQuery = new SysDataDictQuery();
        sysDataDictQuery.setId(id);
        return sysDataDictMapper.getSingle(sysDataDictQuery);
    }
}
